"""
活动日志记录器

提供完整操作记录、活动分析统计、日志查询等功能
"""

import json
import uuid
from datetime import datetime, timedelta
from typing import Dict, List, Any, Optional, Union
from dataclasses import dataclass, asdict
from pathlib import Path
from enum import Enum
import threading
from collections import defaultdict, Counter

from ..interfaces.base_component import BaseComponent


class ActivityType(Enum):
    """活动类型"""
    USER_LOGIN = "user_login"
    USER_LOGOUT = "user_logout"
    DOCUMENT_CREATE = "document_create"
    DOCUMENT_EDIT = "document_edit"
    DOCUMENT_DELETE = "document_delete"
    DOCUMENT_SHARE = "document_share"
    VERSION_CREATE = "version_create"
    VERSION_ROLLBACK = "version_rollback"
    COLLABORATION_JOIN = "collaboration_join"
    COLLABORATION_LEAVE = "collaboration_leave"
    RESEARCH_PLAN_CREATE = "research_plan_create"
    EXPERIMENT_START = "experiment_start"
    EXPERIMENT_COMPLETE = "experiment_complete"
    ANALYSIS_RUN = "analysis_run"
    REPORT_GENERATE = "report_generate"
    SYSTEM_ERROR = "system_error"
    API_CALL = "api_call"


@dataclass
class ActivityRecord:
    """活动记录"""
    id: str
    timestamp: datetime
    activity_type: ActivityType
    user_id: str
    session_id: str
    resource_id: Optional[str]
    resource_type: Optional[str]
    action_details: Dict[str, Any]
    metadata: Dict[str, Any]
    ip_address: Optional[str] = None
    user_agent: Optional[str] = None
    duration_ms: Optional[int] = None
    success: bool = True
    error_message: Optional[str] = None
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            'id': self.id,
            'timestamp': self.timestamp.isoformat(),
            'activity_type': self.activity_type.value,
            'user_id': self.user_id,
            'session_id': self.session_id,
            'resource_id': self.resource_id,
            'resource_type': self.resource_type,
            'action_details': self.action_details,
            'metadata': self.metadata,
            'ip_address': self.ip_address,
            'user_agent': self.user_agent,
            'duration_ms': self.duration_ms,
            'success': self.success,
            'error_message': self.error_message
        }
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'ActivityRecord':
        """从字典创建"""
        return cls(
            id=data['id'],
            timestamp=datetime.fromisoformat(data['timestamp']),
            activity_type=ActivityType(data['activity_type']),
            user_id=data['user_id'],
            session_id=data['session_id'],
            resource_id=data.get('resource_id'),
            resource_type=data.get('resource_type'),
            action_details=data['action_details'],
            metadata=data['metadata'],
            ip_address=data.get('ip_address'),
            user_agent=data.get('user_agent'),
            duration_ms=data.get('duration_ms'),
            success=data.get('success', True),
            error_message=data.get('error_message')
        )


class ActivityLogger(BaseComponent):
    """活动日志记录器"""
    
    def get_required_configs(self) -> List[str]:
        return ['log_storage_path', 'retention_days']
    
    def _setup_component(self):
        """设置组件特定的初始化逻辑"""
        self.logger.info("活动日志记录器初始化")
        
        # 日志存储配置
        self.log_storage_path = Path(self.config.get('log_storage_path', 'activity_logs'))
        self.log_storage_path.mkdir(exist_ok=True)
        
        # 保留天数
        self.retention_days = self.config.get('retention_days', 90)
        
        # 内存缓存
        self.memory_buffer: List[ActivityRecord] = []
        self.buffer_size = self.config.get('buffer_size', 1000)
        
        # 线程锁
        self.buffer_lock = threading.Lock()
        
        # 统计缓存
        self.stats_cache: Dict[str, Any] = {}
        self.stats_cache_expiry = datetime.now()
        self.stats_cache_duration = timedelta(minutes=15)
        
        # 启动后台任务
        self._start_background_tasks()
        
        self.logger.info("活动日志记录器初始化完成")
    
    def log_activity(self,
                    activity_type: ActivityType,
                    user_id: str,
                    session_id: str,
                    action_details: Dict[str, Any],
                    resource_id: Optional[str] = None,
                    resource_type: Optional[str] = None,
                    metadata: Optional[Dict[str, Any]] = None,
                    ip_address: Optional[str] = None,
                    user_agent: Optional[str] = None,
                    duration_ms: Optional[int] = None,
                    success: bool = True,
                    error_message: Optional[str] = None) -> str:
        """记录活动"""
        try:
            # 创建活动记录
            record = ActivityRecord(
                id=str(uuid.uuid4()),
                timestamp=datetime.now(),
                activity_type=activity_type,
                user_id=user_id,
                session_id=session_id,
                resource_id=resource_id,
                resource_type=resource_type,
                action_details=action_details,
                metadata=metadata or {},
                ip_address=ip_address,
                user_agent=user_agent,
                duration_ms=duration_ms,
                success=success,
                error_message=error_message
            )
            
            # 添加到缓冲区
            with self.buffer_lock:
                self.memory_buffer.append(record)
                
                # 检查是否需要刷新到磁盘
                if len(self.memory_buffer) >= self.buffer_size:
                    self._flush_buffer()
            
            return record.id
            
        except Exception as e:
            self.logger.error(f"记录活动失败: {str(e)}")
            return ""
    
    def query_activities(self,
                        user_id: Optional[str] = None,
                        activity_types: Optional[List[ActivityType]] = None,
                        resource_id: Optional[str] = None,
                        start_time: Optional[datetime] = None,
                        end_time: Optional[datetime] = None,
                        limit: int = 100,
                        offset: int = 0) -> List[ActivityRecord]:
        """查询活动记录"""
        try:
            # 从内存缓冲区和磁盘文件中查询
            all_records = []
            
            # 查询内存缓冲区
            with self.buffer_lock:
                all_records.extend(self.memory_buffer)
            
            # 查询磁盘文件
            disk_records = self._load_records_from_disk(start_time, end_time)
            all_records.extend(disk_records)
            
            # 应用过滤条件
            filtered_records = self._filter_records(
                all_records, user_id, activity_types, resource_id, start_time, end_time
            )
            
            # 排序和分页
            filtered_records.sort(key=lambda r: r.timestamp, reverse=True)
            return filtered_records[offset:offset + limit]
            
        except Exception as e:
            self.logger.error(f"查询活动记录失败: {str(e)}")
            return []
    
    def get_user_activity_summary(self, 
                                 user_id: str,
                                 days: int = 7) -> Dict[str, Any]:
        """获取用户活动摘要"""
        try:
            end_time = datetime.now()
            start_time = end_time - timedelta(days=days)
            
            # 查询用户活动
            activities = self.query_activities(
                user_id=user_id,
                start_time=start_time,
                end_time=end_time,
                limit=10000
            )
            
            if not activities:
                return {}
            
            # 统计分析
            activity_counts = Counter(a.activity_type.value for a in activities)
            daily_counts = defaultdict(int)
            hourly_distribution = defaultdict(int)
            resource_usage = defaultdict(int)
            
            for activity in activities:
                # 按天统计
                day_key = activity.timestamp.date().isoformat()
                daily_counts[day_key] += 1
                
                # 按小时统计
                hour_key = activity.timestamp.hour
                hourly_distribution[hour_key] += 1
                
                # 资源使用统计
                if activity.resource_type:
                    resource_usage[activity.resource_type] += 1
            
            # 计算活跃度
            active_days = len(daily_counts)
            avg_daily_activities = sum(daily_counts.values()) / max(active_days, 1)
            
            return {
                'user_id': user_id,
                'period_days': days,
                'total_activities': len(activities),
                'activity_types': dict(activity_counts),
                'daily_counts': dict(daily_counts),
                'hourly_distribution': dict(hourly_distribution),
                'resource_usage': dict(resource_usage),
                'active_days': active_days,
                'avg_daily_activities': round(avg_daily_activities, 2),
                'most_active_hour': max(hourly_distribution.items(), key=lambda x: x[1])[0] if hourly_distribution else None
            }
            
        except Exception as e:
            self.logger.error(f"获取用户活动摘要失败: {str(e)}")
            return {}
    
    def get_system_activity_stats(self, days: int = 30) -> Dict[str, Any]:
        """获取系统活动统计"""
        try:
            # 检查缓存
            if (self.stats_cache and 
                datetime.now() < self.stats_cache_expiry and
                self.stats_cache.get('days') == days):
                return self.stats_cache
            
            end_time = datetime.now()
            start_time = end_time - timedelta(days=days)
            
            # 查询所有活动
            activities = self.query_activities(
                start_time=start_time,
                end_time=end_time,
                limit=50000
            )
            
            if not activities:
                return {}
            
            # 统计分析
            total_activities = len(activities)
            unique_users = len(set(a.user_id for a in activities))
            unique_sessions = len(set(a.session_id for a in activities))
            
            # 活动类型分布
            activity_type_dist = Counter(a.activity_type.value for a in activities)
            
            # 用户活跃度
            user_activity_counts = Counter(a.user_id for a in activities)
            most_active_users = user_activity_counts.most_common(10)
            
            # 错误统计
            error_activities = [a for a in activities if not a.success]
            error_rate = len(error_activities) / total_activities if total_activities > 0 else 0
            
            # 时间分布
            daily_counts = defaultdict(int)
            for activity in activities:
                day_key = activity.timestamp.date().isoformat()
                daily_counts[day_key] += 1
            
            # 性能统计
            duration_activities = [a for a in activities if a.duration_ms is not None]
            avg_duration = (sum(a.duration_ms for a in duration_activities) / 
                          len(duration_activities)) if duration_activities else 0
            
            stats = {
                'period_days': days,
                'total_activities': total_activities,
                'unique_users': unique_users,
                'unique_sessions': unique_sessions,
                'activity_type_distribution': dict(activity_type_dist),
                'most_active_users': most_active_users,
                'error_count': len(error_activities),
                'error_rate': round(error_rate * 100, 2),
                'daily_activity_counts': dict(daily_counts),
                'avg_response_time_ms': round(avg_duration, 2),
                'peak_activity_day': max(daily_counts.items(), key=lambda x: x[1])[0] if daily_counts else None
            }
            
            # 更新缓存
            self.stats_cache = stats
            self.stats_cache_expiry = datetime.now() + self.stats_cache_duration
            
            return stats
            
        except Exception as e:
            self.logger.error(f"获取系统活动统计失败: {str(e)}")
            return {}
    
    def cleanup_old_logs(self) -> int:
        """清理过期日志"""
        try:
            cutoff_date = datetime.now() - timedelta(days=self.retention_days)
            deleted_count = 0
            
            # 清理磁盘文件
            for log_file in self.log_storage_path.glob("*.json"):
                try:
                    # 从文件名提取日期
                    date_str = log_file.stem.split('_')[-1]
                    file_date = datetime.strptime(date_str, "%Y%m%d")
                    
                    if file_date < cutoff_date:
                        log_file.unlink()
                        deleted_count += 1
                        
                except Exception as e:
                    self.logger.warning(f"清理日志文件失败: {log_file}, {str(e)}")
            
            self.logger.info(f"清理过期日志完成，删除 {deleted_count} 个文件")
            return deleted_count
            
        except Exception as e:
            self.logger.error(f"清理过期日志失败: {str(e)}")
            return 0
    
    def _flush_buffer(self):
        """刷新缓冲区到磁盘"""
        try:
            if not self.memory_buffer:
                return
            
            # 按日期分组
            records_by_date = defaultdict(list)
            for record in self.memory_buffer:
                date_key = record.timestamp.date().strftime("%Y%m%d")
                records_by_date[date_key].append(record)
            
            # 写入文件
            for date_key, records in records_by_date.items():
                log_file = self.log_storage_path / f"activity_log_{date_key}.json"
                
                # 读取现有记录
                existing_records = []
                if log_file.exists():
                    try:
                        with open(log_file, 'r', encoding='utf-8') as f:
                            existing_data = json.load(f)
                            existing_records = [ActivityRecord.from_dict(r) for r in existing_data]
                    except Exception as e:
                        self.logger.warning(f"读取现有日志文件失败: {log_file}, {str(e)}")
                
                # 合并记录
                all_records = existing_records + records
                
                # 写入文件
                with open(log_file, 'w', encoding='utf-8') as f:
                    json.dump([r.to_dict() for r in all_records], f, ensure_ascii=False, indent=2)
            
            # 清空缓冲区
            self.memory_buffer.clear()
            
        except Exception as e:
            self.logger.error(f"刷新缓冲区失败: {str(e)}")
    
    def _load_records_from_disk(self, 
                               start_time: Optional[datetime] = None,
                               end_time: Optional[datetime] = None) -> List[ActivityRecord]:
        """从磁盘加载记录"""
        try:
            records = []
            
            # 确定需要读取的文件
            files_to_read = []
            if start_time and end_time:
                current_date = start_time.date()
                end_date = end_time.date()
                while current_date <= end_date:
                    date_key = current_date.strftime("%Y%m%d")
                    log_file = self.log_storage_path / f"activity_log_{date_key}.json"
                    if log_file.exists():
                        files_to_read.append(log_file)
                    current_date += timedelta(days=1)
            else:
                files_to_read = list(self.log_storage_path.glob("activity_log_*.json"))
            
            # 读取文件
            for log_file in files_to_read:
                try:
                    with open(log_file, 'r', encoding='utf-8') as f:
                        data = json.load(f)
                        file_records = [ActivityRecord.from_dict(r) for r in data]
                        records.extend(file_records)
                except Exception as e:
                    self.logger.warning(f"读取日志文件失败: {log_file}, {str(e)}")
            
            return records
            
        except Exception as e:
            self.logger.error(f"从磁盘加载记录失败: {str(e)}")
            return []
    
    def _filter_records(self,
                       records: List[ActivityRecord],
                       user_id: Optional[str] = None,
                       activity_types: Optional[List[ActivityType]] = None,
                       resource_id: Optional[str] = None,
                       start_time: Optional[datetime] = None,
                       end_time: Optional[datetime] = None) -> List[ActivityRecord]:
        """过滤记录"""
        filtered = records
        
        if user_id:
            filtered = [r for r in filtered if r.user_id == user_id]
        
        if activity_types:
            filtered = [r for r in filtered if r.activity_type in activity_types]
        
        if resource_id:
            filtered = [r for r in filtered if r.resource_id == resource_id]
        
        if start_time:
            filtered = [r for r in filtered if r.timestamp >= start_time]
        
        if end_time:
            filtered = [r for r in filtered if r.timestamp <= end_time]
        
        return filtered
    
    def _start_background_tasks(self):
        """启动后台任务"""
        import threading
        import time
        
        def background_worker():
            while True:
                try:
                    # 定期刷新缓冲区
                    time.sleep(60)  # 每分钟检查一次
                    with self.buffer_lock:
                        if self.memory_buffer:
                            self._flush_buffer()
                    
                    # 定期清理过期日志（每天执行一次）
                    if datetime.now().hour == 2:  # 凌晨2点执行
                        self.cleanup_old_logs()
                        
                except Exception as e:
                    self.logger.error(f"后台任务执行失败: {str(e)}")
        
        thread = threading.Thread(target=background_worker, daemon=True)
        thread.start()